<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
    input::-webkit-input-placeholder {    /* Chrome/Opera/Safari */
        color: pink;
    }
    input{
        color: skyblue;
        text-indent: .2em;
    }
    .btn{
        position: absolute;
        cursor: pointer;
        left: 10px;
        top: 34px;
    }
    .box{
        width: 300px;
        height: 300px;
        background-color: skyblue;
        margin: 0 auto;
        cursor: pointer;
    }
    body{
        height: 2000px;
    }
    .demo{
        width: 300px;
        height: 200px;
        border: 1px solid skyblue;
        margin-bottom: 20px;
        .h1{
            color: pink;
        }
    }
    </style>
</head>
<body>
    <input type="text" placeholder="请设置用户名">
    <h1>111</h1>
    <button class="btn">删除按钮</button>
    <ul>
        <li>111</li>
        <li>222</li>
        <li>333</li>
    </ul>
    <div class="box"></div>
    <div class="demo">
        <h1 class="h1">嵌套的h1标签</h1>
    </div>
    <button class="top">返回顶部</button>
</body>
<script>
    // "use strict";
    // var a = 10;
    // function foo () {
    // console.log('this1', this)//w
    // console.log(window.a)//10
    // console.log(this.a)//10
    // }
    // console.log(window.foo)//foo f ()
    // console.log('this2', this) //window
    // foo();

    // var a =10;
    // function fn(){
    //     var a=20;
    //     console.log(this.a);  //会输出全局作用域下的10，因为this指向window(即全局作用域)
    // }
    // fn()

    // 构造函数的继承
    // 构造函数继承缺点：
    //     该方法只能继承父类的方法与属性，不能继承其原型的属性和方法。
    //     每个子类都复制了一份父类的实例对象的属性，函数空间损耗大。
    // function Father(uname,age){
    //     this.uname = uname;
    //     this.age = age;
    //     this.say = function (){
    //         console.log(this.uname+'会唱歌');
    //     }
    // }
    // Father.prototype.sing = function(){
    //     console.log('构造函数原型上的方法');
    // }

    // function Son(uname,age){
    //     Father.apply(this,[uname,age])
    // }
    // const ldh = new Son('刘能',89);
    // ldh.say();
    // console.log(ldh);

    // Array.prototype.sum = function(){
    //     let num = 0;
    //     for(let i=0;i<this.length;i++){
    //         num += this[i]
    //     }
    //     return num
    // }
    // const arr = [1,2,3,4,5]
    // console.log(arr.sum());

    // function fn(...arg){
    //     console.log(arg,this);
    // }
    // const obj = {a:8}
    // fn.bind(obj,1,2,3)()

    // const isValid = false;
    // const age = 18;
    // // 我们可以通过展开运算符向对象添加属性
    // const person = {
    //     id: 'ak001',
    //     name: 'ak47',
    //     ...(!isValid && {isActive: true}),
    //     ...((age > 18 || !isValid) && {cart: 0})
    // }
    // console.log(person)
    
    // let arr = [1,2,3,4,5,6,7,8]
    // let i = 0;

    // switch (i) {
    //     case 0: //这里的判断是i的值的判断
    //         console.log(i);
    //         break;
    //     default:
    //         console.log(9);
    //         break;
    // }

    // do{
    //     console.log(arr[i]);
    // i++;
    // }while(i<arr.length)
    
    // while (i<arr.length) {
    //     console.log(arr[i]);
    //     i++;
    // }
    // Do…while循环与while循环的区别
    // Do…while循环至少执行一次，而while循环可能一次都不执行

    // let obj ={id:1,name:'curry'};
    // // console.log(obj.hasOwnProperty('ids'));//判断一个对象内是否包含某个属性
    // for (const k in obj) {
    //     if(obj[k]&&(typeof obj[k]==='number')){
    //         alert(obj[k]);
    //     }
    // }

//     const fn = (num)=>fun();//箭头函数的简写

//     function fun(){
//         return 999;
//     }
//    console.log(fn());

//    const array  = [5,4,7,8,9,2];
// //    const arrs = array.reduce((a,b)=>{   //找出数组最大值
// //     return a>b?a:b
// //    })
// const arrs = Math.max(...array);
//    console.log(arrs);

// const array  = [5,4,7,8,9,2,7,5,5,4,7,8,9,2,7,5];
// // const ab = array.filter((item,idx,arr) => arr.indexOf(item) === idx);//数组去重
// const ab = [...new Set(array)]
// console.log(ab);


// const obj = {a:1,b:2,c:3,d:1,e:4,f:5,g:3}
// let arr = []
// for (const key in obj) {
//    arr.push(obj[key])
//    arr = [...new Set(arr)]
// }
// console.log(arr);

// const user = { 
//  name: 'Kapil Raghuwanshi', 
//  gender: 'Male' 
//  };
// const college = { 
//  primary: 'Mani Primary School', 
//  secondary: 'Lass Secondary School' 
//  };
// const skills = { 
//  programming: 'Extreme', 
//  swimming: 'Average', 
//  sleeping: 'Pro' 
//  };
// console.log(Object.assign(user,college,skills));


// const user = {
//   employee: {
//     name: {
//         a:18
//     }
//   }
// };
// console.log(user.employee?.name);


// let a = 5;
// let b = 8;
// [a,b] = [b,a];//通过解构交换值
// console.log(a,b);

// function checkPalindrome(str) {
//   return str.split('').reverse().join('');//反转字符串
// }
// console.log(checkPalindrome('curry'));

// const arr = [1,2,3,4,5]
// console.log(arr.at(-1));//5 获取数组成员

// console.log(Array.of(3,2,1));//Array.of将一组值转换为数组

// let arr = [1,2,3]   //第一个参数是要被替换的元素，第二个参数是替换的参数是什么
// console.log(arr.copyWithin(0,2));//注意：它的参数均为下标值//在当前数组内部，将指定位置的成员复制到其他位置（会覆盖原有成员），然后返回当前数组。也就是说，使用这个方法，会修改当前数组。

// let arr = [1, 5, 10, 15].find(function(value, index, arr) {
//   return value > 9;
// })
// console.log(arr);//用于找出第一个符合条件的数组成员。它的参数是一个回调函数，所有数组成员依次执行该回调函数，直到找出第一个返回值为true的成员，然后返回该成员。如果没有符合条件的成员，则返回undefined。

// let arr = [1, 5, 10, 15].findIndex(function(value, index, arr) {
//   return value > 9;
// }) 
// console.log(arr);//数组实例的findIndex()方法的用法与find()方法非常类似，返回第一个符合条件的数组成员的下标，如果所有成员都不符合条件，则返回-1。

// let arr = new Array(3).fill(3);//补充数组
// console.log(arr);


// let arr = ['a', 'b', 'c']
// for (let index of arr.keys()) {
//   console.log(arr[index]);//a,b,c
// }

// for (let elem of arr.values()) {
//   console.log(elem);//a,b,c
// }

// for (let [index, elem] of arr.entries()) {
//   console.log(index, elem);//  0 'a'  1 'b'  2 'c'
// }

// let arr = [1,2,3,4,5]
// // if(arr.includes(3)){
// //     console.log(arr);
// // }
// let newArr = arr.flatMap((x) =>{  //flatMap方法同map方法类似，功能都是加工一个数组返回新数组
//     return x*x
// })
// console.log(newArr);

// console.log(Object.is(NaN, NaN));//Object.is可判断两个值是否全等

let h1 = document.querySelector('h1');
let btn = document.querySelector('.btn');
let ul = document.querySelector('ul');
let ipt = document.querySelector('input')
ipt.onkeypress = function(){ //当按下数字键时被触发
    console.log(111);
} 
btn.onmousedown = function(e){
    console.log(e.offsetX,e.offsetY,e.target);
    let ofx = e.offsetX//如果设置了绝对定位相对自身的位置
    let ofy = e.offsetY//如果设置了绝对定位相对自身的位置
    document.onmousemove = function (e) {
        // console.log(e.pageX,e.pageY);//相对document的位置
        //left
        let left = e.pageX - ofx
        if (left <= 0) {
            left = 0
        }
        // innerWidth属性返回窗口内容区域的宽度，innerHeight属性返回窗口内容区域的高度
        // offsetWidth  //返回盒模型的宽度（包括width+左右padding+左右border）
        // offsetHeight  //返回盒模型的高度（包括height+上下padding+上下border）
        let maxLeft = window.innerWidth - btn.offsetWidth
        if (left > maxLeft) {
            left = maxLeft
        }
        //top
        let top = e.pageY - ofy
        if (top <= 0) {
            top = 0
        }
        let maxTop = window.innerHeight - btn.offsetHeight
        if (top > maxTop) {
            top = maxTop
        }
        //设置一下元素的top和left
        btn.style.left = left + 'px'
        btn.style.top = top + 'px'
        };
        //重置onmousemove事件
        document.onmouseup = function () {
            document.onmousemove = null;
        }
        }
        document.addEventListener('visibilitychange',function(){
        if(document.visibilityState=='hidden'){
            // 切换离开该标签页时触发
            console.log('我要离开此页面啦');
        }else if(document.visibilityState=='visible'){
            // 切换进入该标签页时触发
            console.log('我要进入此页面啦');
        }
        });

    let box = document.querySelector('.box');
    box.addEventListener("mouseenter",(e)=>{
        console.log(e);
        console.log(e.offsetY,e.offsetX);//相对于自身盒子的宽高
        console.log(e.clientX,e.clientY);//相对于浏览器的水平与垂直坐标
        console.log(e.pageX,e.pageY);//相对于整个网页的水平与垂直坐标
        console.log(e.screenX,e.screenY);//相对于整个电脑屏幕的水平与垂直坐标
    })
    let lis = document.querySelectorAll('ul>li')
    ul.addEventListener('click',(e)=>{
        e.stopPropagation();
        e.preventDefault();
        lis.forEach(el=>{
            el.style.color = '';
        })
        e.target.style.color = 'pink';
    })

    let obj = {a:1,b:2,c:3}
    Object.defineProperties(obj, {
        name: {
            value: '祖宗',
            enumerable: false,  //不可枚举
        },
        age: {
            value: 88,
            enumerable: true,   //可枚举
        }
    })
    // console.log('__proto__' in obj,obj); // '属性名' in Object:即使一个属性不在当前的对象上，但是属于其原型链上的一个属性，其结果也是返回true
    //hasOwnProperty() 方法会返回一个布尔值，指示对象自身属性中（非继承属性）是否具有指定的属性，
    // 如果 object 具有带指定名称的属性，则 hasOwnProperty 方法返回 true，否则返回 false。此方法不会检查对象原型链中的属性；该属性必须是对象本身的一个成员。
    // console.log(obj.propertyIsEnumerable('name'),obj);//检测一个属性是一个对象的自身属性且是可枚举的时候才会返回true，否则返回false
    // console.log(window.innerWidth,window.innerHeight);//浏览器窗口内容区域的宽高，不包含控制台的宽高(如果有滚动条则包含滚动条的宽高)
    // console.log(window.outerWidth,window.outerHeight);//整个电脑屏幕的宽高
    // console.log(document.documentElement.clientWidth,document.documentElement.clientHeight);//浏览器窗口内容区域的宽高，不包含控制台的宽高(如果有滚动条则不包含滚动条的宽高)
    let goTop = document.querySelector('.top');
    goTop.onclick = function(){
        document.documentElement.scrollTop = 0;
        // window.scrollY = 0; //但是要注意：这种方法无法让滚动条放回顶部，因为window.scrollY是只读属性，document.documentElement.scrollTop是可改属性
    }
    window.addEventListener('scroll',function(){
        console.log(document.documentElement.scrollTop,window.scrollY);//两个属性都是获取滚动条滚动的距离
    })
</script>
</html>